#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "Element.hpp"
#include "String.hpp"
#include "Text.hpp"
#include <stdio.h>

using namespace xml;

static unsigned int BIG_SZ = 100;

static vector<st_chNM *> stack;

int Element::count = 0;

mem_pool *pool = NULL;

Element::Element(){

	if (pool == NULL){
		if (count == 0){
			pool = (mem_pool *)malloc(BIG_SZ * sizeof (mem_pool));
			if (!pool){
				cout << " Not able to allocate bigger chuck of memory\n";
				assert (false);
			}
			for (unsigned int i = 0; i < BIG_SZ; i ++){
				pool[i].isfree = 0;
			}
		}
	}
	children = 0;
	count ++;
}

Element::~Element(){
	
	if (count != 0){
		for (int i = 0; i < children; i++){
			delete ele_nodes.back();
			ele_nodes.pop_back();
		}
	}
	
	if (count == 1){
		if (pool){
			free(pool);
			pool = NULL;
		}	
	}
	--count ;	
}

void * Element::operator new(size_t sz){

	if (count == 0){
		pool = (mem_pool *)malloc(BIG_SZ * sizeof (mem_pool));
		if (!pool){
			cout << " Not able to allocate bigger chuck of memory\n";
			assert (false);
		}
		for (unsigned int i = 0; i < BIG_SZ; i ++){
			pool[i].isfree = 0;
		}
		count ++;
	}

	int pos = 0;
	unsigned int i = 0;
	for ( i = 0; i < BIG_SZ; i++){
		if (pool[i].isfree == 0)
		{
			pool[i].isfree = 1;
			pos = i;
			break;
		}
	}
	if (i == BIG_SZ){
		unsigned int tmp = BIG_SZ;
		BIG_SZ *= 2;
		pool = (mem_pool *) realloc (pool, BIG_SZ * sizeof(mem_pool));
		for (unsigned int i = tmp; i < BIG_SZ; i++)
			pool[i].isfree = 0;

		pool[tmp].isfree = 1;	
		pos = tmp;
	}
	return (void*)&pool[pos].base;
} 

void Element::operator delete(void *p){

	int *val;
	char *x;
	Element *ptr = (Element *)p;
	x = (char*)(&(ptr)) - sizeof(int);
	val = (int*)x;
	*val = 0;
	if (count == 1){
		if (pool){
			free(pool);
			pool = NULL;
			count --;
		}
	}
}

void Element::addName (const String nm){

	ele_name.assign(nm);
}

const String& Element::name() const{
	return ele_name;
}

void Element::addChildNMSpace (const String nm, const String qt){
	st_chNM c1; // = new st_chNM;
	c1.nm.assign(nm);
	c1.uri.assign(qt);
	child_nmspace.push_back (c1);	
}

void Element::addNMSpace (const String nm){
	ele_namespace.assign(nm);
}

int Element::nm_child(){
	return child_nmspace.size();
}


const String& Element::nmspace() const{
	
	return ele_namespace;
}

void Element::addNode (Node *nd){
	ele_nodes.push_back(nd);
	children++;
}

size_t Element::n_children () const{
	return children;
}

const Node *Element::child (size_t i) const{
	return ele_nodes[i];
}

bool Element::is_Element (const Node *ele){
	
	if (typeid(*ele) == typeid(Element))
		return true;
	else
		return false;
}

const Element * Element::to_Element (const Node *nd){
	return dynamic_cast<const Element *>(nd);
}


void Element::accept (Visitor *visit) const{
	//TODO:
	visit->start_element_visit(*this);
	for (int i = 0; i < this->children; i++) {
		if (Element::is_Element(ele_nodes[i])) {
			const Element *e = Element::to_Element(ele_nodes[i]);
			e->accept(visit);
		}
		else if (Text::is_Text(ele_nodes[i])) {

		        const Text *t = Text::to_Text(ele_nodes[i]);
			visit->visit_text(*t);
		}	
	}	
	visit->end_element_visit(*this);
}

